<?php
/**
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT		: Rubik Ultimate Framework
 * @version 	: 1.1
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * Created on	:  Jun 19, 2008
 * 
 */

// no direct access
defined ( '_FW_EXEC' ) or die ( 'Restricted access' );

class AbstractController extends Object {
	
	/**
	 * Array of class methods to call for a given task.
	 *
	 * @var	array
	 * @access	protected
	 */
	var $_taskMap = null;
	
	/**
	 * Current or most recent task to be performed.
	 *
	 * @var	string
	 * @access	protected
	 */
	var $_task = null;
	
	/**
	 * Array of class methods
	 * @var	array
	 * @access	protected
	 */
	var $_methods = null;
	
	/**
	 * URL for redirection.
	 *
	 * @var	string
	 * @access	protected
	 */
	var $_redirect = null;
	
	/**
	 * Execute by act, task, or option?
	 *
	 * @var string
	 */
	var $_executeBy = null;
	
	/**
	 * Constructor
	 *
	 */
	function __construct() {
		$this->_redirect = null;
		$this->_taskMap = array ();
		$this->_methods = array ();
		// Get the methods only for the final controller class
		$thisMethods = get_class_methods ( get_class ( $this ) );
		$baseMethods = get_class_methods ( 'AbstractController' );
		$methods = array_diff ( $thisMethods, $baseMethods );
		
		// Add default display method
		$methods [] = 'display';
		
		// Iterate through methods and map tasks
		foreach ( $methods as $method ) {
			if (substr ( $method, 0, 1 ) != '_') {
				$this->_methods [] = strtolower ( $method );
				// auto register public methods as tasks
				$this->_taskMap [strtolower ( $method )] = $method;
			}
		}
		$this->registerDefaultTask ( 'display' );
	}
	
	/**
	 * Execute a task by triggering a method in the derived class.
	 *
	 * @access	public
	 * @param	string The task to perform. If no matching task is found, the
	 * '__default' task is executed, if defined.
	 * @return	mixed|false The value returned by the called method, false in
	 * error case.
	 * 
	 */
	function execute($task, $useDefault = true) {
		$this->_task = $task;
		
		$task = strtolower ( $task );
		
		//		if ($task == 'cancel') {
		//			return $this->cancel();
		//		}
		

		// Record the actual task being fired
		if (isset ( $this->_taskMap [$task] )) {
			$doTask = $this->_taskMap [$task];
		} elseif (isset ( $this->_taskMap ['__default'] ) && $useDefault) {
			$doTask = $this->_taskMap ['__default'];
		} else {
			return RError::raiseError ( 404, SysLanguage::_ ( $this->getExecuteBy(). ' [' . $task . '] not found' ) );
		}

		$retval = $this->$doTask ();
		return $retval;
	}
	
	/**
	 * Execute by act, task, or option?
	 *
	 * @param string $by (act, task, or option)
	 * @return	mixed|false The value returned by the called method, 
	 * 			false in error case.
	 */
	function executeBy($by) {
		$this->_executeBy = $by;
		$res = &SysRequest::getResource();
		return $this->execute ( $res->getValueOf ( $by ) );
	}
	
	/**
	 * Get the next excute code of current
	 *
	 * @return string
	 */
	function getNextExcute() {
		switch ($this->_executeBy) {
			case 'app': 
				return 'act';
			case 'act':
				return 'task';
			case 'task':
				return 'option';
			default:
				return null;
		}
	}
	
	/**
	 * Register (map) a task to a method in the class.
	 *
	 * @access	public
	 * @param	string	The task.
	 * @param	string	The name of the method in the derived class to perform
	 *                  for this task.
	 * @return	void
	 * 
	 */
	function registerTask($task, $method) {
		if (in_array ( strtolower ( $method ), $this->_methods )) {
			$this->_taskMap [strtolower ( $task )] = $method;
		}
	}
	
	/**
	 * Register the default task to perform if a mapping is not found.
	 *
	 * @access	public
	 * @param	string The name of the method in the derived class to perform if
	 * a named task is not found.
	 * @return	void
	 * 
	 */
	function registerDefaultTask($method) {
		$this->registerTask ( '__default', $method );
	}
	
	/**
	 * Default Task.
	 * 
	 */
	function display() {
		return;
	}
	
	/**
	 * Redirects the browser.
	 *
	 * @access	public
	 * 
	 */
	function redirect() {
		if (empty ( $this->_redirect )) {
			return;
		}
		/*
		 * If the headers have been sent, then we cannot send an additional location header
		 * so we will output a javascript redirect statement.
		 */
		if (headers_sent ()) {
			echo "<script>document.location.href='$this->_redirect';</script>\n";
		} else {
			header ( 'HTTP/1.1 301 Moved Permanently' );
			header ( 'Location: ' . $this->_redirect );

		}
		exit ();
	}
	
	/**
	 * Set a URL for browser redirection.
	 *
	 * @access	public
	 * @param	string URL to redirect to.
	 * @return	void
	 * 
	 */
	function setRedirect($url) {
		$this->_redirect = $url;
	}
	
	/**
	 * Set a redirect to a function
	 *
	 * @access	public
	 * @param	string URL to redirect to.
	 * @return	void
	 * 
	 */
	function setRedirectToFunction($function, $msg = '') {
		$link = $this->getLinkToFunction($function, $msg);
		if (strpos($link, 'http') === 0 || strpos($link, '/') === 0) {
			$this->_redirect = $link;
		}
		else {
			$this->_redirect = SYS_ROOT_URL . $link;
		}
	}
	
	/**
	 * Set a redirect to the current function
	 *
	 * @access	public
	 * @param	string $msg.
	 * @return	void
	 * 
	 */
	function setRedirectToCurrentFunction($msg = '') {
		$this->setRedirectToFunction($this->getExecuteVal(), $msg);
	}
	
	/**
	 * get the redirect link to a function
	 *
	 * @access	public
	 * @param	string URL to redirect to.
	 * @return	string
	 */
	function getLinkToFunction($function, $msg = '') {
		$listAllowHost = SysRequest::cloneResource ();
		$listAllowHost->removeExtendWithoutPrefix();
		if ($msg) {
			$listAllowHost->setExtend ( "msg", $msg );
		}
		$listAllowHost->setExtend ( $this->getExecuteBy (), $function );
		$link = $listAllowHost->getLink ();
		return $link;
	}
	
	/**
	 * Get the execute value (the value of act, task, 
	 * or option that the controller run
	 *
	 * @return string
	 */
	function getExecuteVal() {
		return $this->_task;
	}
	
	/**
	 * Get the name of execute by, 
	 * this may be "act"/"task"/"option"
	 *
	 * @return string
	 */
	function getExecuteBy() {
		return $this->_executeBy;
	}
	
	/**
	 * Add a button into the toolbar
	 *
	 * @param string $executeVal the execute val that the system will trigger when user click on this toolbar
	 * @param string $title
	 * @param string $attribute
	 * @param string $executeBy by default this will get the current $executeBy of this object
	 * @param boolean $checkBackEnd should check the back end before add the toolbar?
	 */
	function addToolbarButton($executeVal, $title = '', $attribute = '', $executeBy = null, $checkBackEnd = true) {
		if ($checkBackEnd && ! SystemSite::isBackEnd ()) {			
			return;
		}
		if (empty ( $executeBy )) {
			$executeBy = $this->getExecuteBy ();			
		}
		switch ($executeBy) {
			case "option" :
				SysAdminHeader::addOptionButton ( $executeVal, $title, $attribute );
				break;
			case "task" :
				SysAdminHeader::addTaskButton ( $executeVal, $title, $attribute );
				break;
			case "act" :
				SysAdminHeader::addActButton ( $executeVal, $title, $attribute );
				break;
		}
	}
	
	/**
	 * Set the title page for the back-end
	 *
	 * @param string $title
	 * @param string $checkBackend
	 */
	function setTitle($title, $checkBackend = true) {
		if ($checkBackend && ! SystemSite::isBackEnd ()) {
			return;
		}
		SysAdminHeader::setTitle ( $title );
	}
	
	/**
	 * Append the title after the existing one. 
	 *
	 * @param string $title
	 * @param string $connector
	 * @param string $checkBackend
	 */
	function appendTitle($title, $connector = ' -> ', $checkBackend = true) {
		if ($checkBackend && ! SystemSite::isBackEnd ()) {
			return;
		}
		SysAdminHeader::appendTitle( $title, $connector);
	}
}
?>
